#include "Preprocessing.h"

AdaptiveThreshold::AdaptiveThreshold(struct PreprocessParam &preprocess_param)//形参是一个结构体的指针变量preprocess_param
{
    this->preprocess_param = &preprocess_param;//this指针指向preprocess_param，并存放preprocess_param的地址
}

Preprocessing::Preprocessing()//构造函数
{
    element_size = 5;//初始化element_size尺寸为5
}

Preprocessing::~Preprocessing()//析构函数（为了释放空间）
{
    element1 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1, 5));//定义element1存放返回的形状（矩形）和大小
    element2 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 7));//定义element2存放返回的形状（矩形）和大小
}

//自定义阈值操作
void AdaptiveThreshold::adaptiveThresholdProc(cv::Mat src, cv::Mat &dst, int method, int morphology, int iteration, int filter)//输入图像-输出图像-要使用的自适应阈值算法-
{
    switch (method)//选择模式
    {
    case 0:  // red       
    {
        std::vector<cv::Mat> rgbChannels(3);//定义一个Mat类型的三通道数组
        cv::split(src, rgbChannels);//分离源图像的颜色通道
        cv::Mat gray = rgbChannels[2] - rgbChannels[0];//定义Mat类型的gray用于存放通道2与通道0的像素差
        cv::threshold(gray, dst, preprocess_param->gray_thre_min, 255, cv::THRESH_BINARY);//固定阈值操作
        break;
    }
    case 1:  // blue   
    {
        std::vector<cv::Mat> rgbChannels(3);//定义一个Mat类型的三通道数组
        cv::split(src, rgbChannels);//分离源图像的颜色通道
        cv::Mat gray = rgbChannels[0] - rgbChannels[2];//定义Mat类型的gray用于存放通道0与通道0的像素差
        cv::threshold(gray, dst, preprocess_param->gray_thre_min, 255, cv::THRESH_BINARY);//固定阈值操作
        break;
    }
    case 2:  // red过曝光
    {
        mulAndIterRedTre(src, dst, preprocess_info_rune);//调用函数
    }
    case 3:  // blue过曝光
    {
        mulAndIterBlueTre(src, dst, preprocess_info_rune);//调用函数
    }
    default:
        break;
    }
}

void AdaptiveThreshold::mulAndIterRedTre(cv::Mat src, cv::Mat &bin, PreprocessInfo &preprocess_info)//红色通道的函数
{
    cv::Mat gray_g = cv::Mat::zeros(src.size(), CV_8UC1);//初始化gray_g为原图像的大小，且为单通道
    cv::Mat gray_r = cv::Mat::zeros(src.size(), CV_8UC1);//初始化gray_r为原图像的大小，且为单通道

    // 因为常量会比变量快，所以当图像通道确定时，所以通道用常量
    int srcRows = src.cols * 3;
    for(int i = 0; i < src.rows; i++)
    {
        uchar *p_src = src.data+srcRows * i;//src首地址+src.cols * 3*i生成的新地址赋给*p_src
        uchar *p_gray_g = gray_g.data + gray_g.cols * i;//gray_g的首地址+gray_g的总列数*i生成的新地址赋给*p_gray_g
        uchar *p_gray_r = gray_r.data + gray_r.cols * i;//gray_r的首地址+gray_r的总列数*i生成的新地址赋给*p_gray_r
        int jj = 0;
        for(int j = 0; j < srcRows; j += 3)
        {
            *(p_gray_g + jj) = *(p_src + j + 1);//将p_src的地址+j+1后，取当前地址的值赋给（p_gray_g 地址+ jj）这个地址对应的值
            *(p_gray_r + jj) = *(p_src + j) * 0.1 + *(p_src + j + 1) * 0.2 + *(p_src + j + 2) * 0.7;//（（p_src的地址 + j ，取当前地址对应的值）*0.1+（p_src的地址 + j +1，取当前地址对应的值）*0.2+（p_src的地址 + j +2，取当前地址对应的值）*0.7）赋给（p_gray_r的地址 + jj）对应的值
            jj++;//每循环一次jj加1
        }
    }
    // 最大灰度
    uchar gray_max = gray_r.data[0];//定义最大灰度值为gray_r地址首元素的灰度值
    for(int i = 0; i < gray_r.rows; i++)//遍历gray_r整个图像
    {
        uchar *p = gray_r.data + i * gray_r.cols;//gray_r首地址+i*gray_r的总列数赋给*p
        for(int j = 0; j < gray_r.cols; j++)
        {
            if(*(p + j) > gray_max)//p的地址+j后对应的灰度值，如果大于定义的最大灰度值，进行下面操作
                gray_max = *(p + j);//将此时的灰度值定为最大的灰度值
        }
    }

    int &thre = preprocess_info.thre;//preprocess_info.thre这个值赋作thre的地址
    thre = gray_max * preprocess_param->gray_max_w / 10. + avgGrayThreshold(gray_r) * preprocess_param->gray_avg_w / 1.;
    //thre的值为最大灰度值*gray_max_w的地址/10加上avgGrayThreshold（）函数返回值*gray_avg_w的地址/1；

    VAL_LIMIT(thre, preprocess_param->gray_thre_min, preprocess_param->gray_thre_max);

    cv::threshold(gray_r, bin, thre, 255, 0);//固定阈值操作   0代表THRESH_BINARY
}

void AdaptiveThreshold::mulAndIterBlueTre(cv::Mat src, cv::Mat &bin, PreprocessInfo &preprocess_info)//蓝色通道的函数
{
    cv::Mat gray_b = cv::Mat::zeros(src.size(), CV_8UC1);//初始化gray_b为原图像的大小，且为单通道
    cv::Mat gray_g = cv::Mat::zeros(src.size(), CV_8UC1);//初始化gray_g为原图像的大小，且为单通道

    int srcRows = src.cols * 3;
    for(int i = 0; i < src.rows; i++)
    {
        uchar *p_src = src.data + srcRows * i;//src首地址+src.cols * 3*i生成的新地址赋给*p_src
        uchar *p_gray_b = gray_b.data + gray_b.cols * i;//gray_b的首地址+gray_b的总列数*i生成的新地址赋给*p_gray_b
        uchar *p_gray_g = gray_g.data + gray_g.cols * i;//gray_g的首地址+gray_g的总列数*i生成的新地址赋给*p_gray_g

        int jj = 0;
        for(int j = 0; j < srcRows; j += 3)
        {
            *(p_gray_b + jj) = *(p_src + j) * 0.7 + *(p_src + j + 1) * 0.2 + *(p_src + j + 2) * 0.1; //（（p_src的地址 + j ，取当前地址对应的值） * 0.1 + （p_src的地址 + j + 1，取当前地址对应的值） * 0.2 + （p_src的地址 + j + 2，取当前地址对应的值） * 0.7）赋给（p_gray_r的地址 + jj）对应的值
            *(p_gray_g + jj) = *(p_src + j + 1);//将p_src的地址+j+1后，取当前地址的值赋给（p_gray_g 地址+ jj）这个地址对应的值
            jj++;//每循环一次jj加1
        }
    }
    //最大灰度
    uchar gray_max = gray_b.data[0];//定义最大灰度值为gray_r地址首元素的灰度值
    for(int i = 0; i < gray_b.rows; i++)//遍历gray_b整个图像
    {
        uchar *p = gray_b.data + i * gray_b.cols;//gray_b首地址+i*gray_b的总列数赋给*p
        for(int j = 0; j < gray_b.cols; j++)
        {
            if(*(p + j) > gray_max)//p的地址+j后对应的灰度值，如果大于定义的最大灰度值，进行下面操作
                gray_max = *(p + j);//将此时的灰度值定为最大的灰度值
        }
    }

    int &thre = preprocess_info.thre;//将preprocess_info.thre当作thre的地址
    thre = gray_max * preprocess_param->gray_max_w / 10. + avgGrayThreshold(gray_b) * preprocess_param->gray_avg_w / 1.;
    //thre的值为最大灰度值*gray_max_w的地址/10加上avgGrayThreshold（）函数返回值*gray_avg_w的地址/1；
    VAL_LIMIT(thre, preprocess_param->gray_thre_min, preprocess_param->gray_thre_max);

    cv::threshold(gray_b, bin, thre, 255, 0);//固定阈值操作   0代表THRESH_BINARY
}

int AdaptiveThreshold::avgGrayThreshold(cv::Mat src)//对源图像的操作
{
    long sum_gray = 0;
    for(int j = 0; j < src.rows; j++)//两个for循环遍历整个图像
    {
        uchar *data = src.ptr<uchar>(j);//将第j行的像素的地址赋给指针data
        for(int i = 0; i < src.cols; i++)
        {
            sum_gray += data[i];//对第j行对应第i列的像素的灰度值进行加和
        }
    }
    return sum_gray * 1.0 / (src.cols * src.rows);//遍历完整个图像后返回的灰度总值的比例
}

void AdaptiveThreshold::filter(cv::Mat &dst)//对输出图像的操作
{
    //cv::erode(dst, dst, element1);
    cv::dilate(dst, dst, element2);//对输出图像膨胀操作

//    setStructElement();
//    cv::morphologyEx(dst, dst, cv::MORPH_OPEN, element);
//    cv::morphologyEx(dst, dst,cv::MORPH_CLOSE,element);
    cv::medianBlur(dst, dst, 3);//用中值滤波再次处理图像
}
